package org.feng;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.WriteSheet;
import enums.ExcelHeadBeanFlagEnum;
import enums.SexEnum;
import factory.ExcelHeadMapFactory;
import headbean.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.function.BiFunction;

@Controller
@RequestMapping("/excel")
public class ExcelDemoController {

    @GetMapping("/exportDy")
    public String exportDy(@RequestParam("flag")String flag,
                           @RequestParam("table")List<String> table, HttpServletResponse response) throws IOException {
        String fileName = System.currentTimeMillis() + ".xlsx";

        Class<? extends ExcelHeadMapInterface> headClass = ExcelHeadBeanFlagEnum.getHeadClass(flag);
        Map<String, String> namedPrepareHeadMap = ExcelHeadMapFactory.getHeadMap(headClass);
        Map<String, Object> head = new LinkedHashMap<>();
        for (String fieldName : table) {
            head.put(namedPrepareHeadMap.get(fieldName), fieldName);
        }

        List<Map<String, Object>> excelDataList = new ArrayList<>();
        excelDataList.add(head);

        // 制造假数据
        for (BiFunction<Class<? extends ExcelHeadMapInterface>, List<Map<String, Object>>, Boolean> biFunction : bizList) {
            Boolean applied = biFunction.apply(headClass, excelDataList);
            if(applied) {
                break;
            }
        }

        byte[] bytes = easyOut(excelDataList);
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setContentType("application/x-msdownload");
        response.setCharacterEncoding("utf-8");
        response.getOutputStream().write(bytes);
        response.getOutputStream().flush();

        return "success";
    }

    static final List<BiFunction<Class<? extends ExcelHeadMapInterface>, List<Map<String, Object>>, Boolean>> bizList = new ArrayList<>();

    @PostConstruct
    private void init() {
        bizList.add(this::genStudentDemoData);
        bizList.add(this::genNameAndFactoryDemoData);
    }


    private boolean genStudentDemoData(Class<? extends ExcelHeadMapInterface> headClass, List<Map<String, Object>> excelDataList) {
        if(headClass == StudentDemo.class) {
            Map<String, Object> headMap = excelDataList.get(0);
            for (int i = 0; i < 5; i++) {
                Collection<Object> fieldNames = headMap.values();


                Map<String, Object> data = new ExcelDataLinkedHashMap(new ArrayList<>(fieldNames), headClass);
                excelDataList.add(data);

                data.put("name", "张三"+(i+1));
                data.put("age", "年龄"+(i+1));
                data.put("studentNo", "学号"+(i+1));
                data.put("className", "班级"+(i+1));
                data.put("sex", i % 2 == 1 ? SexEnum.FEMALE : SexEnum.MALE);
            }
            return true;
        }
        return false;
    }

    private boolean genNameAndFactoryDemoData(Class<? extends ExcelHeadMapInterface> headClass, List<Map<String, Object>> excelDataList) {
        if(headClass == NameAndFactoryDemo.class) {
            Map<String, Object> headMap = excelDataList.get(0);
            for (int i = 0; i < 5; i++) {
                Collection<Object> fieldNames = headMap.values();
                Map<String, Object> data = new ExcelDataLinkedHashMap(new ArrayList<>(fieldNames), headClass);
                excelDataList.add(data);
                data.put("name", "张三"+(i+1));
                data.put("factory", "工厂"+(i+1));
            }
            return true;
        }
        return false;
    }



    /**
     * 导出数据（单sheet）
     * @param exportData key 是sheet名称，value是每个sheet里面的数据，支持自定义表头
     */
    public static byte[] easyOut(List<Map<String, Object>> exportData) {
        return easyOut(Collections.singletonMap("Sheet", exportData));
    }

    /**
     * 导出数据（多sheet）
     * @param exportData key 是sheet名称，value是每个sheet里面的数据，可以自定义
     */
    public static byte[] easyOut(Map<String, List<Map<String, Object>>> exportData) {
        // 导出数据
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        com.alibaba.excel.ExcelWriter excelWriter = EasyExcel.write(out).build();
        int i=0;
        for (Map.Entry<String, List<Map<String, Object>>> entry: exportData.entrySet()) {
            WriteSheet writeSheet = EasyExcel.writerSheet(i, entry.getKey()).head(head(entry.getValue().get(0))).build();
            i++;
            excelWriter.write(data(entry.getValue(), true), writeSheet);
        }
        excelWriter.finish();

        return out.toByteArray();
    }

    private static List<List<String>> head(Map<String, Object> cellData) {
        List<List<String>> head = new ArrayList<>();
        for (String key: cellData.keySet()) {
            head.add(Collections.singletonList(key));
        }
        return head;
    }

    private static List<List<Object>> data(List<Map<String, Object>> sheetData, boolean skipHead) {
        List<List<Object>> data = new ArrayList<>();
        for (int i = 0; i < sheetData.size(); i++) {
            if(i == 0 && skipHead) {
                continue;
            }
            data.add(new ArrayList<>(sheetData.get(i).values()));
        }
        return data;
    }
}
